There are total 27 positions where players can be placed in a football field but there are only 11 players on a pitch, at a time, for one team including goalkeeper. So, there’s need to be a way to cluster the positions in order to have understandable plots. There are three basic ways to cluster the positions which is shown below:
- Clustering based on basic positions assigned to them
- Attackers - ST,CF,RF,LF,RS,LS,CF,LW,RW
- Defenders - LB,RB,RWB,LWB,RCB,CB,LCB
- Midfielders - RCM,LCM,CAM,RM,LAM,LM,CM,RAM,LDM,CDM,RDM
- Clustering based on flanks in which they play
- Left Attack - LW,LS,LF
- Center Attack - ST,CF
- Right Attack - RW,RS,RF
- Left Midfield - LAM,LM,LDM,LCM
- Center Midfield - CAM,CM,CDM
- Right Midfield - RAM,RM,RDM,RCM
- Left Defense - LB,LWB
- Center Defense - LCB,RCB,CB
- Right Defense - RB,RWB
- Clustering based on the roles they perform
- Strikers - ST,CF,RF,LF,RS,LS,CF
- Wingers - LW,RW
- Attacking Midfield - RCM,LCM,CAM,RM,LAM,LM,CM,RAM
- Defensive Midfield - LDM,CDM,RDM
- Full backs - LB,RB,RWB,LWB
- Center Back - RCB,CB,LCB
The number of unique clubs in the dataset is 651. In order to filter the data a little, for the next few plots, we have considered only the clubs which are included in the top 5 leagues of Europe. The Leagues are as below:
- Bundesliga Country: Germany, Clubs: 18
- Premier League Country: England, Clubs: 20
- LaLiga Country: Spain, Clubs: 20
- Ligue1 Country: France, Clubs: 20
- Serie A Country: Italy, Clubs: 17
The number of clubs shown here is according to the year 2019.
#library imports
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
import plotly.offline as py
#file imports
Nationality = pd.read_csv('Nationality.csv')
Position = pd.read_csv('Foot_Position.csv')
WeakFoot = pd.read_csv('WeakFoot.csv')
Moves = pd.read_csv('Moves.csv')
Leagues = pd.read_csv('Leagues.csv')
# Plot 1 (Distribution of Weak Foot of players among different Positions)
WeakFoot["Weak_Foot"] = WeakFoot["Weak_Foot"].astype(str)
fig = px.bar(WeakFoot, x='Post', y='Player_Count', color = 'Weak_Foot', barmode='group')
fig.update_xaxes(title_text='Positions in Football Field')
fig.update_yaxes(title_text='Number of Players')
fig.update_layout(title_text='Disribution of Weak Foot ratings at different Positions', xaxis={'categoryorder':'array', 'categoryarray':['Defenders','Midfielders','Attackers']})
py.plot(fig, filename = "WeakFoot.html", auto_open=False)
# To show the interactive plotly plot
htmltools::includeHTML("WeakFoot.html")
The bar plot above shows how the ratings of the weak foot of the players is spread over three different positions (Clustering 2).
The Weak Foot Skill measures the ability of a player to shoot with one foot as he does with his preferred foot. All players have a preferred foot. Having a 5-star weak foot rating means that a player’s weaker foot shot is identical to their preferred foot shot. Having a 2-star weak foot rating means that the player can only shoot OK with one foot. Majority of footballers have the average of 3 star week foot. This can be clearly depicted from the plot that despite the position majority lies in 3 star weak-foot pile, although midfielder and striker positions have better ratio of players with better than average weak foot, 4 or 5 star weak foot.
# Plot2 (Distribution of Skill Moves of players among different Positions)
Moves["Skill_Moves"] = Moves["Skill_Moves"].astype(str)
fig = px.bar(Moves, x='Post', y='Player_Count', color = 'Skill_Moves', barmode='group')
fig.update_xaxes(title_text='Different Positions in Football')
fig.update_yaxes(title_text='Number of Players')
fig.update_layout(title_text='Distribution of Star Skill Moves at different Positions', xaxis={'categoryorder':'array', 'categoryarray':['Defenders','Midfielders','Attackers']})
py.plot(fig, filename = "SkillMoves.html", auto_open=False)
# To show the interactive plotly plot
htmltools::includeHTML("SkillMoves.html")
This bar plot shows the distribution of the Skill moves which is from 1 to 5 at three different positions based on Clustering 1 as mentioned above.
The Star Skill Moves measures the ability that a player has to perform technical moves. To all skill moves are assigned a number between 1 (least complex) and 5 (most complex). The players with higher skills, as Ronaldo or Neymar, are able to perform more complex moves. The job of defender does not require performing skills as they just have to stop opposition from moving forward and/or pass the ball to the midfield. This is well supported with the plot which shows that majority of defenders have, low, 2 star skill moves and rest with 3 star skill moves. Skill moves rating improves for midfielders and strikers as they need a bit of complex moves to break into the oppositions defense and score goals. It is also clear that there are no players with the worst skill moves (i.e. 1).
#Plot 3 (Comparison of Different Players's Position w.r.t their Preferred Foot)
fig = px.bar(Position, x='Post', y='Player_Count', color = 'Preferred_Foot', barmode='group')
fig.update_xaxes(title_text='Different Positions in Football')
fig.update_yaxes(title_text='Number of Players')
fig.update_layout(title_text='Comparison of different positions w.r.t their Preferred Foot', xaxis={'categoryorder':'array', 'categoryarray':['Left Attacking', 'Left Back', 'Left Midfielder','Center Attacking','Center Back','Center Midfielder', 'Right Attacking','Right Back','Right Midfielder']})
py.plot(fig, filename = "PreferredFoot.html", auto_open=False)
# To show the interactive plotly plot
htmltools::includeHTML("PreferredFoot.html")
This bar plot is plotted against the number of players vs their different positions. The coloring is varied by their preferred foot and the clustering performed here is based on their flanks (Clustering 2).
Every footballer has a preferred foot, either right or left. This plot shows very interesting outcome that certain positions have more left players than right foot players and also certain position have extremely less left players. It can be stated based on this that certain positions are better suited for right or left footed players. For example, majority of left back players are left footed which is exactly opposite for right back players with majority of right foot players.
#Plot 4 (Distribution of Home Grown and Foreign Players in Various Leagues)
fig = px.bar(Nationality, x='League', y='Group_Count', color = 'Diverse', barmode='group')
fig.update_layout(title_text='Distribution of Home grown vs Foreign Players')
fig.update_xaxes(title_text='Leagues')
fig.update_yaxes(title_text='Number of Players')
py.plot(fig, filename = "Nationality.html", auto_open=False)
# To show the interactive plotly plot
htmltools::includeHTML("Nationality.html")
The above bar plot shows the amount of the players playing for either their home country or foreign country from top 5 leagues in Europe.
The Premier League has the highest number of foreign players playing for England whereas Bundesliga has almost the same amount of home grown and foreign players. LaLiga has more Spanish players than foreign players and the same trend is seen for the Ligue1 as well. However, SerieA has less players of their nationality but also the number of players in SerieA is quite less than players in Premier League.
Leagues['International_Reputation'] = Leagues['International_Reputation'].astype(int)
fig = px.scatter(Leagues, y="Wage(Euro)", x="Age", size = 'International_Reputation', color="International_Reputation", hover_name="Name", size_max=20)
fig.update_yaxes(title_text='Weekly Wage of the Players')
fig.update_xaxes(title_text='Age of the players')
fig.update_layout(title_text='Weekly Wages of the players against their Age')
py.plot(fig, filename = "Wages.html", auto_open=False)
htmltools::includeHTML("Wages.html")
The scatter plot shown here is plotted against the weekly wage of the players (in euro) against their ages. The size and the color of the points is associated with the player’s International Reputation.
Football might be one of the highest paid professions but it is also one of the shortest span profession, rarely a professional football player plays more than 10 years in pro football. This plot provide insights of highly competitive behavior of the football world. Football demands high strength and stamina from all the players on pitch irrespective of the position they play in. Hence, age can be best compared with wage of the players. As in every other profession, performance is directly related to salary and so is in football but in a very volatile way. Majority of the professional footballers are in between 20 and 35 years of age which best represents the competition and robustness of football world. Best paid footballers are all between 26 and 33 years of age which is the peak of any footballer’s career. International reputation depends on how good a player plays for their national team. As seen in plot, it is directly related with wage of a player. To summarize, competition increases with age until you reach your early thirties and then decreases. Also wage increases with increasing competition, if you play well and, better the wage better is the international reputation.
LS0tDQp0aXRsZTogIkNoYXB0ZXIgMyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQpUaGVyZSBhcmUgdG90YWwgMjcgcG9zaXRpb25zIHdoZXJlIHBsYXllcnMgY2FuIGJlIHBsYWNlZCBpbiBhIGZvb3RiYWxsIGZpZWxkIGJ1dCB0aGVyZSBhcmUgb25seSAxMSBwbGF5ZXJzIG9uIGEgcGl0Y2gsIGF0IGEgdGltZSwgZm9yIG9uZSB0ZWFtIGluY2x1ZGluZyBnb2Fsa2VlcGVyLiBTbywgdGhlcmXigJlzIG5lZWQgdG8gYmUgYSB3YXkgdG8gY2x1c3RlciB0aGUgcG9zaXRpb25zIGluIG9yZGVyIHRvIGhhdmUgdW5kZXJzdGFuZGFibGUgcGxvdHMuIFRoZXJlIGFyZSB0aHJlZSBiYXNpYyB3YXlzIHRvIGNsdXN0ZXIgdGhlIHBvc2l0aW9ucyB3aGljaCBpcyBzaG93biBiZWxvdzoNCg0KMS4JQ2x1c3RlcmluZyBiYXNlZCBvbiBiYXNpYyBwb3NpdGlvbnMgYXNzaWduZWQgdG8gdGhlbQ0KDQogIEEuCUF0dGFja2VycyAtIFNULENGLFJGLExGLFJTLExTLENGLExXLFJXDQogIEIuCURlZmVuZGVycyAtIExCLFJCLFJXQixMV0IsUkNCLENCLExDQg0KICBDLglNaWRmaWVsZGVycyAtIFJDTSxMQ00sQ0FNLFJNLExBTSxMTSxDTSxSQU0sTERNLENETSxSRE0NCg0KMi4JQ2x1c3RlcmluZyBiYXNlZCBvbiBmbGFua3MgaW4gd2hpY2ggdGhleSBwbGF5DQoNCiAgQS4JTGVmdCBBdHRhY2sgLSBMVyxMUyxMRg0KICBCLglDZW50ZXIgQXR0YWNrIC0gU1QsQ0YNCiAgQy4JUmlnaHQgQXR0YWNrIC0gUlcsUlMsUkYNCiAgRC4JTGVmdCBNaWRmaWVsZCAtIExBTSxMTSxMRE0sTENNDQogIEUuCUNlbnRlciBNaWRmaWVsZCAtIENBTSxDTSxDRE0NCiAgRi4JUmlnaHQgTWlkZmllbGQgLSBSQU0sUk0sUkRNLFJDTQ0KICBHLglMZWZ0IERlZmVuc2UgLSBMQixMV0INCiAgSC4JQ2VudGVyIERlZmVuc2UgLSBMQ0IsUkNCLENCDQogIEkuCVJpZ2h0IERlZmVuc2UgLSBSQixSV0INCg0KMy4JQ2x1c3RlcmluZyBiYXNlZCBvbiB0aGUgcm9sZXMgdGhleSBwZXJmb3JtDQoNCiAgQS4JU3RyaWtlcnMgLSBTVCxDRixSRixMRixSUyxMUyxDRg0KICBCLglXaW5nZXJzIC0gTFcsUlcNCiAgQy4JQXR0YWNraW5nIE1pZGZpZWxkIC0gUkNNLExDTSxDQU0sUk0sTEFNLExNLENNLFJBTQ0KICBELglEZWZlbnNpdmUgTWlkZmllbGQgLSBMRE0sQ0RNLFJETQ0KICBFLglGdWxsIGJhY2tzIC0gTEIsUkIsUldCLExXQg0KICBGLglDZW50ZXIgQmFjayAtIFJDQixDQixMQ0INCg0KVGhlIG51bWJlciBvZiB1bmlxdWUgY2x1YnMgaW4gdGhlIGRhdGFzZXQgaXMgNjUxLiBJbiBvcmRlciB0byBmaWx0ZXIgdGhlIGRhdGEgYSBsaXR0bGUsIGZvciB0aGUgbmV4dCBmZXcgcGxvdHMsIHdlIGhhdmUgY29uc2lkZXJlZCBvbmx5IHRoZSBjbHVicyB3aGljaCBhcmUgaW5jbHVkZWQgaW4gdGhlIHRvcCA1IGxlYWd1ZXMgb2YgRXVyb3BlLiBUaGUgTGVhZ3VlcyBhcmUgYXMgYmVsb3c6DQoNCjEuCUJ1bmRlc2xpZ2EgDQogICAgICBDb3VudHJ5OiBHZXJtYW55LCAgQ2x1YnM6IDE4DQoyLglQcmVtaWVyIExlYWd1ZSANCiAgICAgIENvdW50cnk6IEVuZ2xhbmQsIENsdWJzOiAyMA0KMy4JTGFMaWdhIA0KICAgICAgQ291bnRyeTogU3BhaW4sIENsdWJzOiAyMA0KNC4JTGlndWUxIA0KICAgICAgQ291bnRyeTogRnJhbmNlLCBDbHViczogMjANCjUuCVNlcmllIEEgDQogICAgICBDb3VudHJ5OiBJdGFseSwgQ2x1YnM6IDE3DQoNClRoZSBudW1iZXIgb2YgY2x1YnMgc2hvd24gaGVyZSBpcyBhY2NvcmRpbmcgdG8gdGhlIHllYXIgMjAxOS4NCg0KYGBge3B5dGhvbn0NCiNsaWJyYXJ5IGltcG9ydHMNCmltcG9ydCBwYW5kYXMgYXMgcGQNCmltcG9ydCBudW1weSBhcyBucA0KaW1wb3J0IHBsb3RseS5ncmFwaF9vYmplY3RzIGFzIGdvDQppbXBvcnQgcGxvdGx5LmV4cHJlc3MgYXMgcHgNCmltcG9ydCBwbG90bHkub2ZmbGluZSBhcyBweQ0KYGBgDQoNCmBgYHtweXRob259DQojZmlsZSBpbXBvcnRzDQpOYXRpb25hbGl0eSA9IHBkLnJlYWRfY3N2KCdOYXRpb25hbGl0eS5jc3YnKQ0KUG9zaXRpb24gPSBwZC5yZWFkX2NzdignRm9vdF9Qb3NpdGlvbi5jc3YnKQ0KV2Vha0Zvb3QgPSBwZC5yZWFkX2NzdignV2Vha0Zvb3QuY3N2JykNCk1vdmVzID0gcGQucmVhZF9jc3YoJ01vdmVzLmNzdicpDQpMZWFndWVzID0gcGQucmVhZF9jc3YoJ0xlYWd1ZXMuY3N2JykNCmBgYA0KDQpgYGB7cHl0aG9ufQ0KIyBQbG90IDEgKERpc3RyaWJ1dGlvbiBvZiBXZWFrIEZvb3Qgb2YgcGxheWVycyBhbW9uZyBkaWZmZXJlbnQgUG9zaXRpb25zKQ0KV2Vha0Zvb3RbIldlYWtfRm9vdCJdID0gV2Vha0Zvb3RbIldlYWtfRm9vdCJdLmFzdHlwZShzdHIpDQpmaWcgPSBweC5iYXIoV2Vha0Zvb3QsIHg9J1Bvc3QnLCB5PSdQbGF5ZXJfQ291bnQnLCBjb2xvciA9ICdXZWFrX0Zvb3QnLCBiYXJtb2RlPSdncm91cCcpDQpmaWcudXBkYXRlX3hheGVzKHRpdGxlX3RleHQ9J1Bvc2l0aW9ucyBpbiBGb290YmFsbCBGaWVsZCcpDQpmaWcudXBkYXRlX3lheGVzKHRpdGxlX3RleHQ9J051bWJlciBvZiBQbGF5ZXJzJykNCmZpZy51cGRhdGVfbGF5b3V0KHRpdGxlX3RleHQ9J0Rpc3JpYnV0aW9uIG9mIFdlYWsgRm9vdCByYXRpbmdzIGF0IGRpZmZlcmVudCBQb3NpdGlvbnMnLCB4YXhpcz17J2NhdGVnb3J5b3JkZXInOidhcnJheScsICdjYXRlZ29yeWFycmF5JzpbJ0RlZmVuZGVycycsJ01pZGZpZWxkZXJzJywnQXR0YWNrZXJzJ119KQ0KcHkucGxvdChmaWcsIGZpbGVuYW1lID0gIldlYWtGb290Lmh0bWwiLCBhdXRvX29wZW49RmFsc2UpDQpgYGANCg0KYGBge3J9DQojIFRvIHNob3cgdGhlIGludGVyYWN0aXZlIHBsb3RseSBwbG90DQpodG1sdG9vbHM6OmluY2x1ZGVIVE1MKCJXZWFrRm9vdC5odG1sIikNCmBgYA0KDQoNClRoZSBiYXIgcGxvdCBhYm92ZSBzaG93cyBob3cgdGhlIHJhdGluZ3Mgb2YgdGhlIHdlYWsgZm9vdCBvZiB0aGUgcGxheWVycyBpcyBzcHJlYWQgb3ZlciB0aHJlZSBkaWZmZXJlbnQgcG9zaXRpb25zIChDbHVzdGVyaW5nIDIpLg0KDQpUaGUgV2VhayBGb290IFNraWxsIG1lYXN1cmVzIHRoZSBhYmlsaXR5IG9mIGEgcGxheWVyIHRvIHNob290IHdpdGggb25lIGZvb3QgYXMgaGUgZG9lcyB3aXRoIGhpcyBwcmVmZXJyZWQgZm9vdC4gQWxsIHBsYXllcnMgaGF2ZSBhIHByZWZlcnJlZCBmb290LiBIYXZpbmcgYSA1LXN0YXIgd2VhayBmb290IHJhdGluZyBtZWFucyB0aGF0IGEgcGxheWVy4oCZcyB3ZWFrZXIgZm9vdCBzaG90IGlzIGlkZW50aWNhbCB0byB0aGVpciBwcmVmZXJyZWQgZm9vdCBzaG90LiBIYXZpbmcgYSAyLXN0YXIgd2VhayBmb290IHJhdGluZyBtZWFucyB0aGF0IHRoZSBwbGF5ZXIgY2FuIG9ubHkgc2hvb3QgT0sgd2l0aCBvbmUgZm9vdC4gTWFqb3JpdHkgb2YgZm9vdGJhbGxlcnMgaGF2ZSB0aGUgYXZlcmFnZSBvZiAzIHN0YXIgd2VlayBmb290LiBUaGlzIGNhbiBiZSBjbGVhcmx5IGRlcGljdGVkIGZyb20gdGhlIHBsb3QgdGhhdCBkZXNwaXRlIHRoZSBwb3NpdGlvbiBtYWpvcml0eSBsaWVzIGluIDMgc3RhciB3ZWFrLWZvb3QgcGlsZSwgYWx0aG91Z2ggbWlkZmllbGRlciBhbmQgc3RyaWtlciBwb3NpdGlvbnMgaGF2ZSBiZXR0ZXIgcmF0aW8gb2YgcGxheWVycyB3aXRoIGJldHRlciB0aGFuIGF2ZXJhZ2Ugd2VhayBmb290LCA0IG9yIDUgc3RhciB3ZWFrIGZvb3QuDQoNCg0KYGBge3B5dGhvbn0NCiMgUGxvdDIgKERpc3RyaWJ1dGlvbiBvZiBTa2lsbCBNb3ZlcyBvZiBwbGF5ZXJzIGFtb25nIGRpZmZlcmVudCBQb3NpdGlvbnMpDQpNb3Zlc1siU2tpbGxfTW92ZXMiXSA9IE1vdmVzWyJTa2lsbF9Nb3ZlcyJdLmFzdHlwZShzdHIpDQpmaWcgPSBweC5iYXIoTW92ZXMsIHg9J1Bvc3QnLCB5PSdQbGF5ZXJfQ291bnQnLCBjb2xvciA9ICdTa2lsbF9Nb3ZlcycsIGJhcm1vZGU9J2dyb3VwJykNCmZpZy51cGRhdGVfeGF4ZXModGl0bGVfdGV4dD0nRGlmZmVyZW50IFBvc2l0aW9ucyBpbiBGb290YmFsbCcpDQpmaWcudXBkYXRlX3lheGVzKHRpdGxlX3RleHQ9J051bWJlciBvZiBQbGF5ZXJzJykNCmZpZy51cGRhdGVfbGF5b3V0KHRpdGxlX3RleHQ9J0Rpc3RyaWJ1dGlvbiBvZiBTdGFyIFNraWxsIE1vdmVzIGF0IGRpZmZlcmVudCBQb3NpdGlvbnMnLCB4YXhpcz17J2NhdGVnb3J5b3JkZXInOidhcnJheScsICdjYXRlZ29yeWFycmF5JzpbJ0RlZmVuZGVycycsJ01pZGZpZWxkZXJzJywnQXR0YWNrZXJzJ119KQ0KcHkucGxvdChmaWcsIGZpbGVuYW1lID0gIlNraWxsTW92ZXMuaHRtbCIsIGF1dG9fb3Blbj1GYWxzZSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBUbyBzaG93IHRoZSBpbnRlcmFjdGl2ZSBwbG90bHkgcGxvdA0KaHRtbHRvb2xzOjppbmNsdWRlSFRNTCgiU2tpbGxNb3Zlcy5odG1sIikNCmBgYA0KDQoNClRoaXMgYmFyIHBsb3Qgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgU2tpbGwgbW92ZXMgd2hpY2ggaXMgZnJvbSAxIHRvIDUgYXQgdGhyZWUgZGlmZmVyZW50IHBvc2l0aW9ucyBiYXNlZCBvbiBDbHVzdGVyaW5nIDEgYXMgbWVudGlvbmVkIGFib3ZlLg0KDQpUaGUgU3RhciBTa2lsbCBNb3ZlcyBtZWFzdXJlcyB0aGUgYWJpbGl0eSB0aGF0IGEgcGxheWVyIGhhcyB0byBwZXJmb3JtIHRlY2huaWNhbCBtb3Zlcy4gVG8gYWxsIHNraWxsIG1vdmVzIGFyZSBhc3NpZ25lZCBhIG51bWJlciBiZXR3ZWVuIDEgKGxlYXN0IGNvbXBsZXgpIGFuZCA1IChtb3N0IGNvbXBsZXgpLiBUaGUgcGxheWVycyB3aXRoIGhpZ2hlciBza2lsbHMsIGFzIFJvbmFsZG8gb3IgTmV5bWFyLCBhcmUgYWJsZSB0byBwZXJmb3JtIG1vcmUgY29tcGxleCBtb3Zlcy4gVGhlIGpvYiBvZiBkZWZlbmRlciBkb2VzIG5vdCByZXF1aXJlIHBlcmZvcm1pbmcgc2tpbGxzIGFzIHRoZXkganVzdCBoYXZlIHRvIHN0b3Agb3Bwb3NpdGlvbiBmcm9tIG1vdmluZyBmb3J3YXJkIGFuZC9vciBwYXNzIHRoZSBiYWxsIHRvIHRoZSBtaWRmaWVsZC4gVGhpcyBpcyB3ZWxsIHN1cHBvcnRlZCB3aXRoIHRoZSBwbG90IHdoaWNoIHNob3dzIHRoYXQgbWFqb3JpdHkgb2YgZGVmZW5kZXJzIGhhdmUsIGxvdywgMiBzdGFyIHNraWxsIG1vdmVzIGFuZCByZXN0IHdpdGggMyBzdGFyIHNraWxsIG1vdmVzLiBTa2lsbCBtb3ZlcyByYXRpbmcgaW1wcm92ZXMgZm9yIG1pZGZpZWxkZXJzIGFuZCBzdHJpa2VycyBhcyB0aGV5IG5lZWQgYSBiaXQgb2YgY29tcGxleCBtb3ZlcyB0byBicmVhayBpbnRvIHRoZSBvcHBvc2l0aW9ucyBkZWZlbnNlIGFuZCBzY29yZSBnb2Fscy4gSXQgaXMgYWxzbyBjbGVhciB0aGF0IHRoZXJlIGFyZSBubyBwbGF5ZXJzIHdpdGggdGhlIHdvcnN0IHNraWxsIG1vdmVzIChpLmUuIDEpLg0KDQoNCmBgYHtweXRob259DQojUGxvdCAzIChDb21wYXJpc29uIG9mIERpZmZlcmVudCBQbGF5ZXJzJ3MgUG9zaXRpb24gdy5yLnQgdGhlaXIgUHJlZmVycmVkIEZvb3QpDQpmaWcgPSBweC5iYXIoUG9zaXRpb24sIHg9J1Bvc3QnLCB5PSdQbGF5ZXJfQ291bnQnLCBjb2xvciA9ICdQcmVmZXJyZWRfRm9vdCcsIGJhcm1vZGU9J2dyb3VwJykNCmZpZy51cGRhdGVfeGF4ZXModGl0bGVfdGV4dD0nRGlmZmVyZW50IFBvc2l0aW9ucyBpbiBGb290YmFsbCcpDQpmaWcudXBkYXRlX3lheGVzKHRpdGxlX3RleHQ9J051bWJlciBvZiBQbGF5ZXJzJykNCmZpZy51cGRhdGVfbGF5b3V0KHRpdGxlX3RleHQ9J0NvbXBhcmlzb24gb2YgZGlmZmVyZW50IHBvc2l0aW9ucyB3LnIudCB0aGVpciBQcmVmZXJyZWQgRm9vdCcsIHhheGlzPXsnY2F0ZWdvcnlvcmRlcic6J2FycmF5JywgJ2NhdGVnb3J5YXJyYXknOlsnTGVmdCBBdHRhY2tpbmcnLCAnTGVmdCBCYWNrJywgJ0xlZnQgTWlkZmllbGRlcicsJ0NlbnRlciBBdHRhY2tpbmcnLCdDZW50ZXIgQmFjaycsJ0NlbnRlciBNaWRmaWVsZGVyJywgJ1JpZ2h0IEF0dGFja2luZycsJ1JpZ2h0IEJhY2snLCdSaWdodCBNaWRmaWVsZGVyJ119KQ0KcHkucGxvdChmaWcsIGZpbGVuYW1lID0gIlByZWZlcnJlZEZvb3QuaHRtbCIsIGF1dG9fb3Blbj1GYWxzZSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBUbyBzaG93IHRoZSBpbnRlcmFjdGl2ZSBwbG90bHkgcGxvdA0KaHRtbHRvb2xzOjppbmNsdWRlSFRNTCgiUHJlZmVycmVkRm9vdC5odG1sIikNCmBgYA0KDQoNClRoaXMgYmFyIHBsb3QgaXMgcGxvdHRlZCBhZ2FpbnN0IHRoZSBudW1iZXIgb2YgcGxheWVycyB2cyB0aGVpciBkaWZmZXJlbnQgcG9zaXRpb25zLiBUaGUgY29sb3JpbmcgaXMgdmFyaWVkIGJ5IHRoZWlyIHByZWZlcnJlZCBmb290IGFuZCB0aGUgY2x1c3RlcmluZyBwZXJmb3JtZWQgaGVyZSBpcyBiYXNlZCBvbiB0aGVpciBmbGFua3MgKENsdXN0ZXJpbmcgMikuDQoNCkV2ZXJ5IGZvb3RiYWxsZXIgaGFzIGEgcHJlZmVycmVkIGZvb3QsIGVpdGhlciByaWdodCBvciBsZWZ0LiBUaGlzIHBsb3Qgc2hvd3MgdmVyeSBpbnRlcmVzdGluZyBvdXRjb21lIHRoYXQgY2VydGFpbiBwb3NpdGlvbnMgaGF2ZSBtb3JlIGxlZnQgcGxheWVycyB0aGFuIHJpZ2h0IGZvb3QgcGxheWVycyBhbmQgYWxzbyBjZXJ0YWluIHBvc2l0aW9uIGhhdmUgZXh0cmVtZWx5IGxlc3MgbGVmdCBwbGF5ZXJzLiBJdCBjYW4gYmUgc3RhdGVkIGJhc2VkIG9uIHRoaXMgdGhhdCBjZXJ0YWluIHBvc2l0aW9ucyBhcmUgYmV0dGVyIHN1aXRlZCBmb3IgcmlnaHQgb3IgbGVmdCBmb290ZWQgcGxheWVycy4gRm9yIGV4YW1wbGUsIG1ham9yaXR5IG9mIGxlZnQgYmFjayBwbGF5ZXJzIGFyZSBsZWZ0IGZvb3RlZCB3aGljaCBpcyBleGFjdGx5IG9wcG9zaXRlIGZvciByaWdodCBiYWNrIHBsYXllcnMgd2l0aCBtYWpvcml0eSBvZiByaWdodCBmb290IHBsYXllcnMuDQoNCg0KYGBge3B5dGhvbn0NCiNQbG90IDQgKERpc3RyaWJ1dGlvbiBvZiBIb21lIEdyb3duIGFuZCBGb3JlaWduIFBsYXllcnMgaW4gVmFyaW91cyBMZWFndWVzKQ0KZmlnID0gcHguYmFyKE5hdGlvbmFsaXR5LCB4PSdMZWFndWUnLCB5PSdHcm91cF9Db3VudCcsIGNvbG9yID0gJ0RpdmVyc2UnLCBiYXJtb2RlPSdncm91cCcpDQpmaWcudXBkYXRlX2xheW91dCh0aXRsZV90ZXh0PSdEaXN0cmlidXRpb24gb2YgSG9tZSBncm93biB2cyBGb3JlaWduIFBsYXllcnMnKQ0KZmlnLnVwZGF0ZV94YXhlcyh0aXRsZV90ZXh0PSdMZWFndWVzJykNCmZpZy51cGRhdGVfeWF4ZXModGl0bGVfdGV4dD0nTnVtYmVyIG9mIFBsYXllcnMnKQ0KcHkucGxvdChmaWcsIGZpbGVuYW1lID0gIk5hdGlvbmFsaXR5Lmh0bWwiLCBhdXRvX29wZW49RmFsc2UpDQoNCmBgYA0KDQpgYGB7cn0NCiMgVG8gc2hvdyB0aGUgaW50ZXJhY3RpdmUgcGxvdGx5IHBsb3QNCmh0bWx0b29sczo6aW5jbHVkZUhUTUwoIk5hdGlvbmFsaXR5Lmh0bWwiKQ0KYGBgDQoNCg0KVGhlIGFib3ZlIGJhciBwbG90IHNob3dzIHRoZSBhbW91bnQgb2YgdGhlIHBsYXllcnMgcGxheWluZyBmb3IgZWl0aGVyIHRoZWlyIGhvbWUgY291bnRyeSBvciBmb3JlaWduIGNvdW50cnkgZnJvbSB0b3AgNSBsZWFndWVzIGluIEV1cm9wZS4NCg0KVGhlIFByZW1pZXIgTGVhZ3VlIGhhcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgZm9yZWlnbiBwbGF5ZXJzIHBsYXlpbmcgZm9yIEVuZ2xhbmQgd2hlcmVhcyBCdW5kZXNsaWdhIGhhcyBhbG1vc3QgdGhlIHNhbWUgYW1vdW50IG9mIGhvbWUgZ3Jvd24gYW5kIGZvcmVpZ24gcGxheWVycy4gTGFMaWdhIGhhcyBtb3JlIFNwYW5pc2ggcGxheWVycyB0aGFuIGZvcmVpZ24gcGxheWVycyBhbmQgdGhlIHNhbWUgdHJlbmQgaXMgc2VlbiBmb3IgdGhlIExpZ3VlMSBhcyB3ZWxsLiBIb3dldmVyLCBTZXJpZUEgaGFzIGxlc3MgcGxheWVycyBvZiB0aGVpciBuYXRpb25hbGl0eSBidXQgYWxzbyB0aGUgbnVtYmVyIG9mIHBsYXllcnMgaW4gU2VyaWVBIGlzIHF1aXRlIGxlc3MgdGhhbiBwbGF5ZXJzIGluIFByZW1pZXIgTGVhZ3VlLg0KDQoNCmBgYHtweXRob259DQpMZWFndWVzWydJbnRlcm5hdGlvbmFsX1JlcHV0YXRpb24nXSA9IExlYWd1ZXNbJ0ludGVybmF0aW9uYWxfUmVwdXRhdGlvbiddLmFzdHlwZShpbnQpDQpmaWcgPSBweC5zY2F0dGVyKExlYWd1ZXMsIHk9IldhZ2UoRXVybykiLCB4PSJBZ2UiLCBzaXplID0gJ0ludGVybmF0aW9uYWxfUmVwdXRhdGlvbicsIGNvbG9yPSJJbnRlcm5hdGlvbmFsX1JlcHV0YXRpb24iLCBob3Zlcl9uYW1lPSJOYW1lIiwgc2l6ZV9tYXg9MjApDQpmaWcudXBkYXRlX3lheGVzKHRpdGxlX3RleHQ9J1dlZWtseSBXYWdlIG9mIHRoZSBQbGF5ZXJzJykNCmZpZy51cGRhdGVfeGF4ZXModGl0bGVfdGV4dD0nQWdlIG9mIHRoZSBwbGF5ZXJzJykNCmZpZy51cGRhdGVfbGF5b3V0KHRpdGxlX3RleHQ9J1dlZWtseSBXYWdlcyBvZiB0aGUgcGxheWVycyBhZ2FpbnN0IHRoZWlyIEFnZScpDQpweS5wbG90KGZpZywgZmlsZW5hbWUgPSAiV2FnZXMuaHRtbCIsIGF1dG9fb3Blbj1GYWxzZSkNCg0KYGBgDQoNCmBgYHtyfQ0KaHRtbHRvb2xzOjppbmNsdWRlSFRNTCgiV2FnZXMuaHRtbCIpDQpgYGANCg0KDQpUaGUgc2NhdHRlciBwbG90IHNob3duIGhlcmUgaXMgcGxvdHRlZCBhZ2FpbnN0IHRoZSB3ZWVrbHkgd2FnZSBvZiB0aGUgcGxheWVycyAoaW4gZXVybykgYWdhaW5zdCB0aGVpciBhZ2VzLiBUaGUgc2l6ZSBhbmQgdGhlIGNvbG9yIG9mIHRoZSBwb2ludHMgaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBwbGF5ZXLigJlzIEludGVybmF0aW9uYWwgUmVwdXRhdGlvbi4gDQoNCkZvb3RiYWxsIG1pZ2h0IGJlIG9uZSBvZiB0aGUgaGlnaGVzdCBwYWlkIHByb2Zlc3Npb25zIGJ1dCBpdCBpcyBhbHNvIG9uZSBvZiB0aGUgc2hvcnRlc3Qgc3BhbiBwcm9mZXNzaW9uLCByYXJlbHkgYSBwcm9mZXNzaW9uYWwgZm9vdGJhbGwgcGxheWVyIHBsYXlzIG1vcmUgdGhhbiAxMCB5ZWFycyBpbiBwcm8gZm9vdGJhbGwuIFRoaXMgcGxvdCBwcm92aWRlIGluc2lnaHRzIG9mIGhpZ2hseSBjb21wZXRpdGl2ZSBiZWhhdmlvciBvZiB0aGUgZm9vdGJhbGwgd29ybGQuIEZvb3RiYWxsIGRlbWFuZHMgaGlnaCBzdHJlbmd0aCBhbmQgc3RhbWluYSBmcm9tIGFsbCB0aGUgcGxheWVycyBvbiBwaXRjaCBpcnJlc3BlY3RpdmUgb2YgdGhlIHBvc2l0aW9uIHRoZXkgcGxheSBpbi4gSGVuY2UsIGFnZSBjYW4gYmUgYmVzdCBjb21wYXJlZCB3aXRoIHdhZ2Ugb2YgdGhlIHBsYXllcnMuIEFzIGluIGV2ZXJ5IG90aGVyIHByb2Zlc3Npb24sIHBlcmZvcm1hbmNlIGlzIGRpcmVjdGx5IHJlbGF0ZWQgdG8gc2FsYXJ5IGFuZCBzbyBpcyBpbiBmb290YmFsbCBidXQgaW4gYSB2ZXJ5IHZvbGF0aWxlIHdheS4gTWFqb3JpdHkgb2YgdGhlIHByb2Zlc3Npb25hbCBmb290YmFsbGVycyBhcmUgaW4gYmV0d2VlbiAyMCBhbmQgMzUgeWVhcnMgb2YgYWdlIHdoaWNoIGJlc3QgcmVwcmVzZW50cyB0aGUgY29tcGV0aXRpb24gYW5kIHJvYnVzdG5lc3Mgb2YgZm9vdGJhbGwgd29ybGQuIEJlc3QgcGFpZCBmb290YmFsbGVycyBhcmUgYWxsIGJldHdlZW4gMjYgYW5kIDMzIHllYXJzIG9mIGFnZSB3aGljaCBpcyB0aGUgcGVhayBvZiBhbnkgZm9vdGJhbGxlcuKAmXMgY2FyZWVyLiBJbnRlcm5hdGlvbmFsIHJlcHV0YXRpb24gZGVwZW5kcyBvbiBob3cgZ29vZCBhIHBsYXllciBwbGF5cyBmb3IgdGhlaXIgbmF0aW9uYWwgdGVhbS4gQXMgc2VlbiBpbiBwbG90LCBpdCBpcyBkaXJlY3RseSByZWxhdGVkIHdpdGggd2FnZSBvZiBhIHBsYXllci4gVG8gc3VtbWFyaXplLCBjb21wZXRpdGlvbiBpbmNyZWFzZXMgd2l0aCBhZ2UgdW50aWwgeW91IHJlYWNoIHlvdXIgZWFybHkgdGhpcnRpZXMgYW5kIHRoZW4gZGVjcmVhc2VzLiBBbHNvIHdhZ2UgaW5jcmVhc2VzIHdpdGggaW5jcmVhc2luZyBjb21wZXRpdGlvbiwgaWYgeW91IHBsYXkgd2VsbCBhbmQsIGJldHRlciB0aGUgd2FnZSBiZXR0ZXIgaXMgdGhlIGludGVybmF0aW9uYWwgcmVwdXRhdGlvbi4gDQoNCg==